package cn.edu.scau.cmi.ema.service;

import cn.edu.scau.cmi.ema.base.CmiPagination;
import cn.edu.scau.cmi.ema.domain.Address;
import cn.edu.scau.cmi.ema.domain.Purchaseadditive;
import cn.edu.scau.cmi.ema.domain.Purchasematerial;
import cn.edu.scau.cmi.ema.domain.Supplier;
import cn.edu.scau.cmi.ema.service.base.CmiEmaService;
import cn.edu.scau.cmi.ema.util.CmiSqlUtil;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Query;
import java.util.*;
@Service("SupplierService")
@Transactional

public class SupplierServiceImpl extends CmiEmaService implements SupplierService {
	public SupplierServiceImpl() {
	}

	@Transactional
	public Supplier saveSupplier(Supplier supplier) {
		Set<Purchaseadditive> existingPurchaseadditivesForSupplier = new HashSet<Purchaseadditive>();
		Set<Purchasematerial> existingPurchasematerialsForSupplier = new HashSet<Purchasematerial>();

		Set<Purchaseadditive> selectedPurchaseadditivesForSupplier = supplier.getPurchaseadditivesForSupplier();
		Set<Purchasematerial> selectedPurchasematerialsForSupplier = supplier.getPurchasematerialsForSupplier();

		if (supplier.getId() == null) {
			Address address = addressDAO.findAddressById(supplier.getAddress().getId());

			Supplier existingSupplier = supplierDAO.findSupplierByPhysicalPrimaryKey(supplier.getName(),
					address.getId());

			supplier.setAddress(address);

			if (isEquals(supplier, existingSupplier)) {
				return existingSupplier;
			}

			supplier = supplierDAO.store(supplier);
			supplierDAO.flush();

			for (Purchaseadditive relatedPurchaseadditive : selectedPurchaseadditivesForSupplier) {
				relatedPurchaseadditive.setSupplier(supplier);
				purchaseadditiveDAO.store(relatedPurchaseadditive);
			}
			for (Purchasematerial relatedPurchasematerial : selectedPurchasematerialsForSupplier) {
				relatedPurchasematerial.setSupplier(supplier);
				purchasematerialDAO.store(relatedPurchasematerial);
			}
		} else {
			Supplier existingSupplier = supplierDAO.findSupplierByPrimaryKey(supplier.getId());

			existingPurchaseadditivesForSupplier = existingSupplier.getPurchaseadditivesForSupplier();
			existingPurchasematerialsForSupplier = existingSupplier.getPurchasematerialsForSupplier();

			Set<Purchaseadditive> prepareDeletePurchaseadditivesForSupplier = new HashSet<Purchaseadditive>();
			Set<Purchaseadditive> prepareAddPurchaseadditivesForSupplier = new HashSet<Purchaseadditive>();

			prepareDeletePurchaseadditivesForSupplier.addAll(selectedPurchaseadditivesForSupplier);
			prepareDeletePurchaseadditivesForSupplier.addAll(existingPurchaseadditivesForSupplier);

			prepareAddPurchaseadditivesForSupplier.addAll(selectedPurchaseadditivesForSupplier);
			prepareAddPurchaseadditivesForSupplier.addAll(existingPurchaseadditivesForSupplier);

			prepareDeletePurchaseadditivesForSupplier.removeAll(selectedPurchaseadditivesForSupplier);
			prepareAddPurchaseadditivesForSupplier.removeAll(existingPurchaseadditivesForSupplier);

			for (Purchaseadditive relatedPurchaseadditive : prepareAddPurchaseadditivesForSupplier) {
				relatedPurchaseadditive.setSupplier(supplier);
				purchaseadditiveDAO.store(relatedPurchaseadditive);
			}

			for (Purchaseadditive relatedPurchaseadditive : prepareDeletePurchaseadditivesForSupplier) {
				relatedPurchaseadditive.setSupplier(null);
				purchaseadditiveDAO.store(relatedPurchaseadditive);
			}
			Set<Purchasematerial> prepareDeletePurchasematerialsForSupplier = new HashSet<Purchasematerial>();
			Set<Purchasematerial> prepareAddPurchasematerialsForSupplier = new HashSet<Purchasematerial>();

			prepareDeletePurchasematerialsForSupplier.addAll(selectedPurchasematerialsForSupplier);
			prepareDeletePurchasematerialsForSupplier.addAll(existingPurchasematerialsForSupplier);

			prepareAddPurchasematerialsForSupplier.addAll(selectedPurchasematerialsForSupplier);
			prepareAddPurchasematerialsForSupplier.addAll(existingPurchasematerialsForSupplier);

			prepareDeletePurchasematerialsForSupplier.removeAll(selectedPurchasematerialsForSupplier);
			prepareAddPurchasematerialsForSupplier.removeAll(existingPurchasematerialsForSupplier);

			for (Purchasematerial relatedPurchasematerial : prepareAddPurchasematerialsForSupplier) {
				relatedPurchasematerial.setSupplier(supplier);
				purchasematerialDAO.store(relatedPurchasematerial);
			}

			for (Purchasematerial relatedPurchasematerial : prepareDeletePurchasematerialsForSupplier) {
				relatedPurchasematerial.setSupplier(null);
				purchasematerialDAO.store(relatedPurchasematerial);
			}
			supplier = supplierDAO.store(supplier);
			supplierDAO.flush();
		}

		purchaseadditiveDAO.flush();
		purchasematerialDAO.flush();
		return supplier;
	}

	public void deleteSupplier(Supplier supplier) {
		supplierDAO.remove(supplier);
		supplierDAO.flush();
	}

	@Transactional
	public void deleteSuppliers(Set<Integer> deleteSuppliersId) {
		Query query = supplierDAO.createNamedQuery("deleteSuppliersById", -1, -1);
		query.setParameter(1, deleteSuppliersId);
		query.executeUpdate();
	}

	@Transactional
	public Set<Supplier> loadSuppliers() {
		return supplierDAO.findAllSuppliers();

	}

	@Transactional
	public Set<Supplier> loadReferenceSuppliers(Set<Supplier> suppliers) {
		Iterator<Supplier> suppliersIterator = suppliers.iterator();
		Set<Supplier> referencedSuppliers = new HashSet<>();
		while (suppliersIterator.hasNext()) {
			Supplier currentSupplier = suppliersIterator.next();

			if (!currentSupplier.getPurchaseadditivesForSupplier().isEmpty()) {
				referencedSuppliers.add(currentSupplier);
				continue;
			}

			if (!currentSupplier.getPurchasematerialsForSupplier().isEmpty()) {
				referencedSuppliers.add(currentSupplier);
				continue;
			}
		}
		return referencedSuppliers;
	}

	public Set<Supplier> loadSuppliersByIdSet(Set<Integer> supplierIdSet) {

		Iterator<Integer> supplierIdIterator = supplierIdSet.iterator();
		Set<Supplier> supplierSet = new HashSet<>();
		while (supplierIdIterator.hasNext()) {
			Integer id = supplierIdIterator.next();
			Supplier currentSupplier = supplierDAO.findSupplierById(id);
			supplierSet.add(currentSupplier);
		}
		return supplierSet;
	}

	@Transactional
	public List<Supplier> findAllSuppliers(Integer startResult, Integer maxRows) {
		return new java.util.ArrayList<Supplier>(supplierDAO.findAllSuppliers(startResult, maxRows));
	}

	@Transactional
	public Supplier findSupplierByPrimaryKey(Integer id) {
		return supplierDAO.findSupplierByPrimaryKey(id);
	}

	@Transactional
	public Integer countSuppliers() {
		return ((Long) supplierDAO.createQuerySingleResult("select count(o) from Supplier o").getSingleResult())
				.intValue();
	}

	@Transactional
	public Integer countSuppliers(CmiPagination page) {
		String sql = CmiSqlUtil.createCountHql(page, Supplier.class);
		return ((Long) supplierDAO.createQuerySingleResult(sql).getSingleResult()).intValue();
	}

	/**
	 * search for name with ajax
	 *
	 */
	@Transactional
	public Integer countSuppliersByName(String queryName) {
		Query query = supplierDAO.createNamedQuery("countSuppliersByName", -1, -1);
		query.setParameter(1, queryName);
		return new Long((long) query.getSingleResult()).intValue();
	}

	@Transactional
	public Integer countSuppliersByDetachedCriteria(CmiPagination page) {
		DetachedCriteria detachedCriteria = CmiSqlUtil.createDetachedCriteria(page, Supplier.class);
		Session session = (Session) entityManager.getDelegate();
		detachedCriteria.setProjection(Projections.rowCount());
		return new Long((long) detachedCriteria.getExecutableCriteria(session).uniqueResult()).intValue();
	}

	public Map<String, ?> loadSupplierObjectReferencedSet(Supplier supplier) {
		HashMap<String, Object> objectReferencedSetMap = new HashMap<>();
		if (supplier.getAddress() != null) {

			Set<Integer> addressIds = new HashSet<Integer>();
			addressIds.add(supplier.getAddress().getId());
			objectReferencedSetMap.put("addressIds", addressIds);
		}

		Set<Integer> purchaseadditivesIds = new HashSet<Integer>();
		for (Purchaseadditive obj : supplier.getPurchaseadditivesForSupplier()) {

			purchaseadditivesIds.add(obj.getId());
		}
		objectReferencedSetMap.put("purchaseadditivesIds", purchaseadditivesIds);
		Set<Integer> purchasematerialsIds = new HashSet<Integer>();
		for (Purchasematerial obj : supplier.getPurchasematerialsForSupplier()) {

			purchasematerialsIds.add(obj.getId());
		}
		objectReferencedSetMap.put("purchasematerialsIds", purchasematerialsIds);

		return objectReferencedSetMap;
	}

	public Map<String, ?> loadSupplierClassReferencedSet(Supplier supplier) {
		HashMap<String, Object> classReferencedSetMap = new HashMap<>();
		classReferencedSetMap.put("addresss", addressDAO.findAllAddresss());
		classReferencedSetMap.put("purchaseadditives", purchaseadditiveDAO.findAllPurchaseadditives());
		classReferencedSetMap.put("purchasematerials", purchasematerialDAO.findAllPurchasematerials());

		return classReferencedSetMap;
	}

	public boolean isEquals(Supplier supplier, Object obj) {
		if (obj == supplier)
			return true;
		if (!(obj instanceof Supplier))
			return false;
		Supplier comparedSupplier = (Supplier) obj;
		if (!CheckPropertyEqual(supplier.getName(), comparedSupplier.getName())) {
			return false;
		}
		if (!CheckPropertyEqual(supplier.getAddress().getId(), comparedSupplier.getAddress().getId())) {
			return false;
		}
		return true;
	}

	public static <T> boolean CheckPropertyEqual(T originProperty, T comparedProperty) {
		// 基本类型经过参数传递后会自动装箱
		String[] className = originProperty.getClass().getName().split("\\.");
		if (className[0].equals("java") && className[1].equals("math")) {
			return ((Comparable) originProperty).compareTo(comparedProperty) == 0 ? true : false;
		} else {
			return originProperty.equals(comparedProperty);
		}
	}
}

